package antidestiny.utilib.io;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import antidestiny.utilib.Aide;

/**文件操作工具
 * Created by Hero on 2015/8/7.
 */
public final class FileUtils {
    /**
     * 只含文件(不含文件夹)
     */
    public static ArrayList<File> allFiles(File dir){
        FileFilter fileFilter=new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.isFile();
            }
        };
        return getAll(dir,fileFilter,null);
    }
    public static ArrayList<File> allDirs(File dir){
        FileFilter fileFilter=new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.isDirectory();
            }
        };
        return getAll(dir,fileFilter,null);
    }
    public static ArrayList<File> all(File dir,FileFilter fileFilter){
        return getAll(dir,fileFilter,null);
    }
    public static ArrayList<File> all(File dir,FilenameFilter filenameFilter){
        return getAll(dir,null,filenameFilter);
    }
    /**
     * 遍历文件夹及各级子文件夹找出所有文件和文件夹
     * @param dir 必须是文件夹
     * @return 所有找到的文件.dir不是文件夹时返回空的数组。同一个目录下深层的文件靠前。
     */
    @NonNull
    public static ArrayList<File> getAll(File dir,FileFilter fileFilter,FilenameFilter filenameFilter){
        //包含当前文件夹下面的合适文件和嵌套函数返回的文件
        ArrayList<File> lf=new ArrayList<>();
        if (dir.isFile())return  lf;
        File[] files=dir.listFiles();
        for (File f:files){
            if (f.isDirectory()){
               List<File> l= getAll(f,fileFilter,filenameFilter);
                lf.addAll(l);
            }
            //只有被两个过滤器都接收才可以添加到结果中去。
            if ((fileFilter == null || fileFilter.accept(f))
                    &&(filenameFilter==null||filenameFilter.accept(f.getParentFile(),f.getName())))
                lf.add(f);
        }

     return lf;

    }

    /**
     * 统计子文件夹数量
     * @param dir 文件夹
     */
    public static int getAllSubFileCount(File dir){
        if (dir.isFile())return 0;

        File[] files=dir.listFiles();

        int result=0;
        for(int i=0;i<files.length;i++){
            if (files[i].isFile()) result++;
            else if (files[i].isDirectory())
               result+= getAllSubFileCount(files[i]);

        }
        return result;
    }


    /**
     * 重命名 ，如果文件已经存在，就会在后面加上（1），（2）直到可以创建文件。
     * @param oldFile  要重命名的文件。
     * @param newFile  要重命名成的文件。
     * @return 最终的结果
     */
    public static   File renameFile(File oldFile,File newFile){
        if (oldFile.getPath().equals(newFile.getPath()))
            return oldFile;
        File file=new File(newFile.getPath());
        for (int i=1;file.exists();i++){
            file=new File(newFile.getPath()+
                    '('+i+')');
        }
        boolean b=oldFile.renameTo(file);
        if (!b) Aide.t("重命名文件夹失败");
        return file;

    }

    /**
     * 安全地创建文件。
	 * 如果file的路径不正确（比如一个父文件夹的名字被一个文件占有），可能无法创建文件，返回null。
     * @param file 要创建的文件
     * @param overwrite 如果为false，那么当文件名被占用时就会在文件名后面添加数字1，2，3……；
     * @return 真正被创建的文件，或者是null；
     */
    public static  File createFileSafely(File file,boolean overwrite){
		File parent=file.getParentFile();
        if (parent!=null&&!parent.exists()){
          boolean b=  parent.mkdirs();
            if (!b) return null;
        }

        if (!file.exists()){
            try{
            boolean b=file.createNewFile();
                if (b)return file; else return null;
            }
            catch (Throwable t){
                t.printStackTrace();
            }
        }
        else{
            if (overwrite){
                return file;
            }else{
                String p=file.getParent();
                String format="";
                String name=file.getName();
                if (file.isFile()){
                    int indexOfDot=name.lastIndexOf(".");
                    if (indexOfDot==-1)indexOfDot=name.length();
                    format=name.substring(indexOfDot);
                    name=name.substring(0,indexOfDot);

                }
                for (int i=1;file.exists();i++){
                    file=new File(p+"/"+name+i+format);
                }try {
                    boolean b=file.createNewFile();
                    if (b)return file;else return null;
                }catch (Throwable t){
                    t.printStackTrace();
                }

            }
        }
return null;
    }

    /**
     *
     * @param dir
     * @param cover 覆盖现有文件夹
     * @return 真正创建的文件夹。如果创建失败，返回空
     */
    public static File mkDirsSafely(File dir ,boolean cover){


        if (!dir.exists()){
            try{
                boolean b=dir.mkdirs();
                if (b)return dir; else return null;
            }
            catch (Throwable t){
                t.printStackTrace();
            }
        }
        else{
            if (cover){
                return dir;
            }else{
                String p=dir.getPath();
                for (int i=1;dir.exists();i++){
                    dir=new File(p+'('+i+')');
                }try {
                    boolean b=dir.mkdirs();
                    if (b)return dir;else return null;
                }catch (Throwable t){
                    t.printStackTrace();
                }

            }
        }
        return null;
    }

    public static void write(File file,byte[] bytes){
        FileOutputStream outputStream=null;
        try
        {
            outputStream=new FileOutputStream(file);
            outputStream.write(bytes);
        }catch (Throwable t){
            t.printStackTrace();
        }finally {
            try
            {
                if (outputStream!=null){
                    outputStream.close();
                }
            }catch (Throwable t){
                t.printStackTrace();
            }
        }
    }

    /**
     *
     * @param inputStream 使用后inputstream会关闭
     * @param out
     */
    public static void write(InputStream inputStream,File out) {
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(out);
            int i;
            byte bytes[]=new byte[1024];
            while ((i = inputStream.read(bytes)) != -1) {
                fileOutputStream.write(bytes,0,i);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }
    }

    /**
     * 用过之后inputstream就关闭了；
     * @param inputStream
     * @return
     * @throws IOException
     */

    public static byte[] read(InputStream inputStream)throws IOException{
        return read(inputStream,true);
    }
    public static byte[] read(InputStream inputStream,boolean close)throws IOException {
        byte[] buffer=new byte[1024];
        ByteArrayOutputStream bos=new ByteArrayOutputStream();

       try {
           int count;
           while ((count = inputStream.read(buffer)) != -1) {
               bos.write(buffer, 0, count);
           }
           return bos.toByteArray();
       }finally {
            if (inputStream!=null&&close){
                inputStream.close();
            }
        }
    }
    public static byte[] read(File file){
        FileInputStream fileInputStream=null;
        try
        {fileInputStream=new FileInputStream(file);
            return read(fileInputStream);

        }catch (Throwable t){
            t.printStackTrace();
        }
        return null;
    }

    /**
     * 截取 file 在 指定路径下的路径，比如 file 为/a/b/c，dir为/a，那么结果就是b/c
     * @param file 子文件
     * @param dir 目录
     * @return 如果dir中无法找到file，就为null；
     */
    public static String getSubPath(File file,File dir){
        String a=file.getAbsolutePath();
        String b=dir.getAbsolutePath();
        if (!a.startsWith(b))return  null;

        return a.substring(b.length()+1);
    }
    public static void copy(File file,File aimDir){
        copy(file,aimDir,null);
    }
    public static void copy(File file,File aimDir,Progress progress){
        copy(file,aimDir,progress,false);
    }
    public static void copy(File file,File aimDir,boolean overwrite){
        copy(file,aimDir,null,overwrite);
    }
    public static void copy(File file,File aimDir,Progress percent,boolean overwrite){
        if (!file.exists())return;
        if (file.isFile()){
            File newFile=new File(aimDir.getPath()+"/"+file.getName());
            createFileSafely(newFile, overwrite);
            copyFile(file, newFile);
            if (percent!=null) percent.setI(100);
        }
        else if (file.isDirectory()){
            ArrayList<File > files=
            allFiles(file);

            if (percent!=null)
            percent.setMax(files.size());
            int i=0;
            for (File f:files){
                File newFile=new File(aimDir.getPath()+getSubPath(f,file));
                createFileSafely(newFile,false);
                copyFile(f, newFile);
                i++;
                if (percent!=null)
                percent.setI(i);
            }

        }
    }

    /**
     * 清除文件夹内容而不删除文件夹
     * @param dir 文件夹
     * @param progress 进度，可以为空
     * @return
     */
    public static boolean clearDir(File dir,@Nullable Progress progress){
        boolean success=true;
        ArrayList<File> files=allFiles(dir);
        if (progress!=null){
            progress.setMax(files.size());
        }
        for (File file:files){
            if(!file.delete())success=false;
            if (progress!=null)
            progress.i++;
        }
        files=allDirs(dir);
        for (File file:files){
            if (!file.delete())success=false;
        }
        return success;
    }

    public static boolean removeDir(File dir,@Nullable Progress progress){
        boolean success=true;
        if (!clearDir(dir,progress))success=false;
        if (!dir.delete())success=false;
        return success;
    }

    /**
     * 只能复制文件
     * @param file 源文件
     * @param newFile 目标文件
     */
    private static void copyFile(File file, File newFile){
        FileInputStream fileInputStream=null;
        FileOutputStream fileOutputStream=null;
        try {
            fileInputStream=new FileInputStream(file);
            fileOutputStream=new FileOutputStream(newFile);
            int count;
            byte[] buffer=new byte[1024];
            while((count=fileInputStream.read(buffer))!=-1){
                fileOutputStream.write(buffer,0,count);
            }
        }catch (Throwable t){
            t.printStackTrace();
        }
        finally {
            try{
                if (fileInputStream!=null)fileInputStream.close();
                if (fileOutputStream!=null)fileOutputStream.close();
            }catch (Throwable t){
                t.printStackTrace();
            }
        }
    }

    /**
     * 进行后缀名的比较，不分大小写.
     * @param file
     * @param suffix 有没有以点开头都可以
     * @return file是文件夹时返回假，后缀名匹配返回真
     */
    public static boolean suffixCompare(File file,String suffix){
        return file.isFile()&&suffixCompare(file.getName(),suffix);
    }

    /**
     * 只要有一个后缀匹配即为真
     * @return
     */
    public static boolean suffixCompare(String fileName,String... suffixes){
        for(String suffix:suffixes){
            if (suffixCompare(fileName,suffix))return true;
        }
        return  false;
    }

    /**
     * 假定filename属于一个文件，而不是文件夹
     * @param filename
     * @param suffix 后缀名，比如“.java”或者“java”如果没有点开头会给它加上一个点。
     * @return
     */
    public static boolean suffixCompare(String filename,String suffix){
        if (!suffix.startsWith("."))suffix="."+suffix;
        return filename.regionMatches(true,filename.length() - suffix.length()
                , suffix, 0, suffix.length());
    }



}
